﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

using Perseus;
using Perseus.Data;

using Hetymine.Executioner.Data;

namespace Hetymine.Executioner.Controls {
    /// <summary>
    /// Interaction logic for ListConfigurator.xaml
    /// </summary>
    public partial class ListConfigurator : UserControl, IConfigurator<IConfiguratorList>, ILoader {
        private bool _IsApply = true;

        private IConfiguratorList _List;
        private IConfiguratorItem _SelectedItem;

        private EventHandler _ItemNameChanged;
        private EventHandler _ListChanged;

        private ScrollBarVisibilityEventHandler _ScrollBarVisibilityChanged;
        
        public ListConfigurator() {
            InitializeComponent();

            this.cFilter.TextChanged += new TextChangedEventHandler(Filter_TextChanged);
            this.cList.SelectionChanged += new SelectionChangedEventHandler(List_SelectionChanged);
            this.cAdd.Click += new RoutedEventHandler(Add_Click);
            this.cRemove.Click += new RoutedEventHandler(Remove_Click);
            this.cEdit.ScrollChanged += new ScrollChangedEventHandler(Edit_ScrollChanged);
            this._ItemNameChanged = new EventHandler(ItemNameChanged);
            this._ListChanged += new EventHandler(List_ListChanged);
            this._ScrollBarVisibilityChanged = new ScrollBarVisibilityEventHandler(ScrollBarVisibilityChanged);
        }

        private void Filter_TextChanged(object sender, TextChangedEventArgs e) {
            this.FilterCommandList(this.cFilter.Text);
        }
        private void List_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (!this._IsApply || this._List == null) { return; }

            int index = this.cList.SelectedIndex;

            if (this.cEdit.Content != null && this.cEdit.Content is ILoader) {
                ((ILoader)this.cEdit.Content).Unload();
            }

            if (index < 0) {
                this.cEmptyEdit.Visibility = Visibility.Visible;
                this.cEdit.Content = null;

                // Reset scrollbar visibility to default
                this.cEdit.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
                this.cEdit.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
            }
            else {
                this.cEmptyEdit.Visibility = Visibility.Collapsed;

                // Remove previous event handlers
                if (this._SelectedItem != null) {
                    this._SelectedItem.ItemNameChanged -= this._ItemNameChanged;
                    if (this._SelectedItem is IScrollable) {
                        ((IScrollable)this._SelectedItem).ScrollBarVisibilityChanged -= this._ScrollBarVisibilityChanged;
                    }
                }

                this._SelectedItem = this.SelectedItem();
                this._SelectedItem.ItemNameChanged += this._ItemNameChanged;
                if (this._SelectedItem is IScrollable) {
                    var scrollable = this._SelectedItem as IScrollable;
                    scrollable.ScrollBarVisibilityChanged += this._ScrollBarVisibilityChanged;
                    this.cEdit.HorizontalScrollBarVisibility = scrollable.HorizontalScrollBarVisibility;
                    this.cEdit.VerticalScrollBarVisibility = scrollable.VerticalScrollBarVisibility;
                }
                else {
                    // Reset scrollbar visibility to default
                    this.cEdit.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
                    this.cEdit.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
                }
                this.cEdit.Content = this._SelectedItem.ConfigPanel;
                if (this.cEdit.Content is ILoader) {
                    ((ILoader)this.cEdit.Content).Load();
                }
            }

            // Update the selected index
            this._List.SelectedIndex = index;
            this.UpdateListButtonVisibility();
        }
        private void Add_Click(object sender, RoutedEventArgs e) {
            this._IsApply = false;

            // Remove all empty HotStrings
            for (int i = this._List.Items.Count - 1; i >= 0; i--) {
                if (this._List.Items[i].IsEmpty) {
                    this._List.Items.RemoveAt(i);
                    this.cList.Items.RemoveAt(i);
                }
            }

            this._IsApply = true;

            IConfiguratorItem item = this._List.InitializeItem();

            if (item != null) {
                this._List.Items.Add(item);
                this.cList.Items.Add(this.ListBoxItem(item));
                this.cList.SelectedIndex = this.cList.Items.Count - 1;
                this.cList.ScrollIntoView(this.cList.SelectedItem);
            }
            else {
                Executioner.Sounds.Error();
            }

            this._List.SelectedIndex = this.cList.SelectedIndex;
            this.UpdateListButtonVisibility();
        }
        private void Remove_Click(object sender, RoutedEventArgs e) {
            int index = this.cList.SelectedIndex;
            if (index < 0) { return; }

            this._List.Items.RemoveAt(index);
            this.cList.Items.RemoveAt(index);

            if (this.cList.Items.Count == 0) {
                this.cList.SelectedIndex = -1;
            }
            else if (this.cList.Items.Count <= index) {
                this.cList.SelectedIndex = index - 1;
            }
            else {
                this.cList.SelectedIndex = index;
            }

            this._List.SelectedIndex = this.cList.SelectedIndex;
            this.UpdateListButtonVisibility();
        }
        private void ItemNameChanged(object sender, EventArgs e) {
            IConfiguratorItem item = this.SelectedItem();

            object content = this.ListItemContent(item);

            ((ListBoxItem)this.cList.SelectedItem).Content = content;
        }
        private IConfiguratorItem SelectedItem() {
            int index = this.cList.SelectedIndex;

            return this._List.Items[index];            
        }

        private ListBoxItem ListBoxItem(IConfiguratorItem item) {
            ListBoxItem lbi = new ListBoxItem();

            lbi.Content = this.ListItemContent(item);

            return lbi;
        }
        private object ListItemContent(IConfiguratorItem item) {
            // Empty command
            if (item.IsEmpty) {
                if (this._List.ItemName.IsEmpty()) {
                    return "<empty item>";
                }

                return "<empty " + this._List.ItemName.ToLower() + ">";
            }

            var content = this._List.ListItemContent(item);
            if (content != null) {
                return content;
            }
            
            string name = item.Name;
            if (name.IsEmpty()) {
                return "<no name set>";
            }
                
            return name;
        }
        private void UpdateListButtonVisibility() {
            if (this._List == null) {
                this.cButtons.Visibility = Visibility.Collapsed;
                return;
            }

            bool canAdd = this._List.CanAddItem;
            bool canRemove = this._List.CanRemoveItem;
            if (this.cList.Items.Count == 0) {
                canRemove = false;
            }

            if (!canAdd && !canRemove) {
                this.cButtons.Visibility = Visibility.Collapsed;
                return;
            }

            this.cButtons.Visibility = Visibility.Visible;
            if (!canAdd) {                
                this.cAdd.Visibility = Visibility.Collapsed;
                this.cRemove.Visibility = Visibility.Visible;
            }
            else if (!canRemove) {
                this.cAdd.Visibility = Visibility.Visible;
                this.cRemove.Visibility = Visibility.Collapsed;
            }
            else {
                this.cAdd.Visibility = Visibility.Visible;
                this.cRemove.Visibility = Visibility.Visible;
            }
        }

        #region Scrollbar Handling
        private void Edit_ScrollChanged(object sender, ScrollChangedEventArgs e) {
            // This is pretty hacky, but it works :D
            if (this.cEdit.ComputedVerticalScrollBarVisibility == Visibility.Visible) {
                this.cEdit.Padding = new Thickness(0, 0, 5, 0);
            }
            else {
                this.cEdit.Padding = new Thickness(0);
            }
        }
        private void ScrollBarVisibilityChanged(object sender, ScrollBarVisibilityEventArgs e) {
            this.cEdit.HorizontalScrollBarVisibility = e.HorizontalScrollBarVisibility;
            this.cEdit.VerticalScrollBarVisibility = e.VerticalScrollBarVisibility;
        }
        #endregion

        private void FilterCommandList(string filter) {
            for (int i = 0; i < this._List.Items.Count; ++i) {
                var lbi = this.cList.Items[i] as ListBoxItem;
                var item = this._List.Items[i];

                if (item.IsEmpty || !item.IsMatch(filter)) {
                    lbi.Visibility = System.Windows.Visibility.Collapsed;
                }
                else {
                    lbi.Visibility = System.Windows.Visibility.Visible;
                }
            }
        }
        #region IConfigurator<IConfiguratorList>
        public void InitializeConfig(IConfiguratorList list) {
            // Clean up old list
            if (this._List != null) {
                this._List.ListChanged -= this._ListChanged;
            }

            this._List = list;

            if (list.EditGroupBoxName.IsNotEmpty()) {
                this.cEditGroupBox.Header = list.EditGroupBoxName;
            }

            if (list.ListGroupBoxName.IsNotEmpty()) {
                this.cListGroupBox.Header = list.ListGroupBoxName;
            }

            if (list.ItemName.IsNotEmpty()) {
                this.cEmptyEdit.Text = "<no " + list.ItemName.ToLower() + " selected>";
            }

            this._List.ListChanged += this._ListChanged;
            this.PopulateList();
        }
        private void List_ListChanged(object sender, EventArgs e) {
            this.PopulateList();
        }
        private void PopulateList() {
            this._IsApply = false;

            this.cList.Items.Clear();

            foreach (IConfiguratorItem item in this._List.Items) {
                this.cList.Items.Add(this.ListBoxItem(item));
            }

            this._IsApply = true;

            // If no command is selected, then show empty command message
            if (this._List.SelectedIndex < 0) {
                if (this.cList.Items.Count > 0) {
                    this._List.SelectedIndex = 0;
                    this.cList.SelectedIndex = 0;
                    this.cList.ScrollIntoView(this.cList.SelectedItem);
                }
                else {
                    this.cEmptyEdit.Visibility = Visibility.Visible;
                    this.cEdit.Content = null;
                }
            }
            // If a command is selected, show the commands configurator
            else if (this._List.SelectedIndex >= this.cList.Items.Count) {
                this.cEmptyEdit.Visibility = Visibility.Visible;
                this.cEdit.Content = null;
                this._List.SelectedIndex = -1;
                this.cList.ScrollIntoView(this.cList.SelectedItem);
            }
            else {
                this.cList.SelectedIndex = this._List.SelectedIndex;
                this.cList.ScrollIntoView(this.cList.SelectedItem);
            }

            this.FilterCommandList(this.cFilter.Text);
            this.UpdateListButtonVisibility();
        }
        public UserControl ConfigPanel { get { return this; } }
        #endregion

        #region ILoader Members
        public void Load() {
            // Intentionally left blank
        }
        public void Unload() {
            if (this._List != null) {
                this._List.ListChanged -= this._ListChanged;
            }

            if (this.cEdit.Content != null && this.cEdit.Content is ILoader) {
                ((ILoader)this.cEdit.Content).Unload();
            }
            this.cEdit.Content = null;
        }
        #endregion
    }
}
